Log In  
BBS > Lexaloffle Community Superblog
This is a combined feed of all Lexaloffle user blogs. For Lexaloffle-related news, see @zep's blog.

All | Following | PICO-8 | Voxatron | General | Off-site
[ :: Read More :: ]

Cart #marching_squares-0 | 2024-04-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
2

Basically, I’m working on a digging game and am revisiting something I have worked with in the past: marching squares. I recommend looking it up, but basically the way it works in this project is for each “tile” a table of tables is examined and depending on whether each of the tiles coordinates are on or off the algorithm figure out which sides does the line on the square intersect. Sometime marching squares also uses linear interpolation, but since my screen is stored in binary instead of floating point values I am storing intersection points in separate nested tables. The main thing is that each square is checked, and depending on stored values a specific line might be drawn through it.

This is a basic proof of concept editor, and next up I will probably start to face the horror of adding collisions to this bendy abomination. Also note that my code is probably poorly written so if you want to use it for something you may consider changing some of it to make it take up less valuable space.

Controls:
Directions move the cursor
X implements the current mode
O changes the mode
0-add points of binary
1-delete points of binary
2-edit left side intercept
3-edit top intercept

P#147358 2024-04-26 07:02 ( Edited 2024-04-26 07:07)
[ :: Read More :: ]

Cart #pix-0 | 2024-03-11 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#147341 2024-04-25 22:26 ( Edited 2024-04-25 22:26)
[ :: Read More :: ]
P#147334 2024-04-25 21:53 ( Edited 2024-04-25 21:54)
[ :: Read More :: ]

Cart #ttf0-0 | 2024-04-25 | Embed ▽ | License: CC4-BY-NC-SA
4


based on Sebastian Lague video on how to read a font.
still very early, but got to at least render a missing character glyph.
currently just drag and drop ttf font file onto window.

P#147324 2024-04-25 20:40
[ :: Read More :: ]

Cart #colours-10 | 2024-05-10 | Embed ▽ | License: CC4-BY-NC-SA
11

Colour Reference

A simple and small colour reference utility intended to be ran as a widget, but can still be ran windowed.

Think I'm mostly done with this app now as of v3.0. I have one more idea but I'll probably take a break before doing it and try and move onto something else in the meantime. I have what I want now to help with my development and learned a lot on the way too, hope this app can be useful to you too.

Widget install instructions

To add to your tooltray as a widget add the following line to the /appdata/system/startup.lua

create_process("/filepath/to/Colours.p64",
{
    window_attribs = {workspace = "tooltray", x=0, y=0},
})

change "/filepath/to/Colours.p64" to wherever you save the cart on your system.
I would recommend saving it as /appdata/tooltray/Colours.p64

Customisation

When ran as window the look of the app can be changed via the hamburger menu. To apply the same level of customisation when ran as a widget you can use the following arguments to do so:

  • Chromatic - Change the ordering of the colours to
    be more reminiscent of the editors

  • UseDarkText - Instead of the default way to render
    the text colour on light coloured cells, it will
    use a single darker colour for all light coloured cells.

  • Vertical - Rotates the orientation to be vertical

  • BigFont - use the standard Picotron font rather than
    the smaller Pico 8 font that this app uses by default.

(For the following options, replace # with a number)

  • XSize=# - Specify how wide you want the cells to be.
    Default value is 9, 2 pixels are added when in BigFont
    mode. 9 should be considered the smallest, otherwise
    the font won't align.

  • PaddingSize=# - Specify the extra space in the middle
    'trough' of the palette. Default is 2. When in vertical
    windowed mode, if the overall width of the palette is
    less than 32, the padding will be increased to
    accommodate. This limitation is ignored when used as a
    Widget.

example of create_process command with args:

create_process("/appdata/tooltray/Colours.p64",
{
  window_attribs = {workspace = "tooltray", x=0, y=0},
  argv = {"UseDarkText", "Chromatic" "PaddingSize=4"}
})

The order of the args does not matter

Changelog:

v3.0

  • Added Chromatic ordering that changes the orders of the colours to be more reminiscent of what you see in the editors. This can be changed in the windowed version in the hamburger menu with the Change Ordering option, and can be done for the widget with the Chromatic arg.
  • removed un-needed files from the cart (Actually this time -.-)

v2.3

  • Implemented parsing of args for customising the look of the app when installed as a widget.

v2.2

  • Reimplemented the original default (larger) font version. Changeable via the Change Font option in the hamburger menu.

v2.1

  • Fixed an issue with the padding of the vertical mode persisting when reverting back to horizontal.

v2.0

  • Added Vertical mode - accessed in windowed mode via the Change Orientation option in the hamburger menu. I imagine this will be useful if using a Windowed editor like SLATE rather than the standard fullscreen one.
  • Exposed option to change the way the colours over the light colours are done with the Change Dark Text Style in the hambruger menu (I will make this an arg at some point so it can also be done for when it's a Widget).

v1.3

  • fixed bug where window was still resizeable (thanks OniriCorpe) (somehow this fix wasn't saved to 1.2)

v1.2

  • cleaned up some code, removed previous now unused experiments etc.
  • added comments to code in case people use the code as reference or learning
  • added Widget instructions (same file you can see in cart image) into the cart itself

v1.1

  • Changed the font to the Pico 8 font to slim it down a bunch more.
P#147325 2024-04-25 20:33 ( Edited 2024-05-10 08:07)
[ :: Read More :: ]

Cart #mapshuffle-0 | 2024-04-25 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
4

I made this tool for myself, for reordering levels to fix difficulty curves. But I thought I'd share it in case anyone else finds it useful.

How it works:

  • Press X to select a room, and then X again to swap the two rooms
  • Press C to preview a room
  • Maps are imported/exported manually using cstore. Cry about it :(

Note: Mapshuffle cannot import/export maps in the web player. You must download the cart and use it in immediate mode.

Instructions:

  • Back up your project in case something goes wrong.
  • Download mapshuffle.p8 and place the cart in the same folder as your project.
  • Open your project, type the following line into the terminal, and hit enter:
    cstore(0x0000, 0x0000, 0x3000, "mapshuffle.p8")
  • Now open mapshuffle.p8. The map and sprites should be copied over.
  • Shuffle the map to your heart's content.
  • Once it's done, type this line into the console of mapshuffle.p8, replacing "yourcart.p8" with the name of your project.
    cstore(0x1000, 0x1000, 0x2000, "yourcart.p8")
  • Finally, open your project back up and the shuffled map should be imported.

Also, credits to Maddy Thorson and Noel Berry for making Celeste Classic, which is the default map used in MapShuffle.

P#147322 2024-04-25 19:26 ( Edited 2024-04-25 19:34)
[ :: Read More :: ]

Cart #gorgondel-1 | 2024-04-26 | Embed ▽ | License: CC4-BY-NC-SA
3

My Apple II to #picotron glorious arcade smooth 60fps power portation of this 1981 Nazir Gebelli's classic.

Watch attract mode for instructions!

Ejoy!

rev 2:added gameplay demo to attrack. Humans show up in radar.

P#147314 2024-04-25 16:45 ( Edited 2024-04-26 16:01)
[ :: Read More :: ]

people often ask about object orientation (OOP) and inheritance, but can get confusing or incomplete guides. I want to help everyone understand how prototypes work!

lua does support object-oriented programming (but does not require it), based on prototype inheritance — not classes.
metatables are part of this but also often misunderstood. this is a complete explainer that I wrote on discord and keep not putting here in a clean way. so I am putting it here as it is!

so what is a prototype?

goblin={
 sp=42,
}

function goblin:new(x,y)
 local obj={x=x, y=y}
 return setmetatable(obj, {__index=self})
end

function goblin:draw()
 spr(self.sp,self.x,self.y)
end

gob1=goblin:new(40,40)
gob2=goblin:new(60,70)

alright so this is like 6 different things working together.

1) table with methods: goblin is a table with property sp and methods new and draw (a method is a function attached to an object)

calling goblin:new(40,40) is the same as goblin.new(self,40,40); self is «the object we are working on»; defining function goblin:draw() is the same as function goblin.draw(self) and the same as goblin={sp=42, draw=function(self) spr(...) end, somethingelse=true}

there is a difference between the two methods in my example: when we call goblin:new, the self param inside it will be the goblin table itself (the prototype), but when we have gob1:draw() then self inside draw will refer to gob1.

2) metatables. there are special methods that lua uses to implement operators (+, /, .., etc). the method for addition for example is __add (we call these metamethods). if I want to be able to do vector1 + vector2for my custom vector tables for example, I need to define a method named __add but I can’t do it in the vector prototype table, lua will not look it there; it is required to define these metamethods in a table’s metatable. (the metatable is similar to a class in other object-oriented languages: it is the template, or the definition, or the model for many tables.) so that’s what happens in goblin:new: I define a metatable with one metamethod and set it on my goblin object.

3) prototype. these are great! if I have 50 goblins on screen and they have different health and coordinates but the same properties for sprite, width, height, etc, and the same methods for update, attack, draw, etc, I would like to define all the shared things in one place, then have custom things in each goblin table. that’s what a prototype is for! here in goblin example we have sp and draw shared, and in a specific goblin table (it starts as obj on line 6, then it’s gob1 or gob2 in my example) we have specific data like x and y.
much more info on this really useful site: https://gameprogrammingpatterns.com/prototype.html

alright so how do I say «gob1 and gob2 should delegate to goblin prototype for some properties»? I define a metatable with an __index property. it is called by lua when I do gob1.sp and sp is not found inside gob1. it can be a function (can be useful to have a dynamic property that’s computed from other properties) or another table: the prototype!
more: https://www.lua.org/pil/13.4.1.html

now this is the cool thing with prototype-based object-oriented language that you don’t have in such a nice way with class-based OO languages
what if I want 40 goblins on screen and 10 archer goblins? these should have a different sprite and different attack method.

archer=goblin:new()

archer.sp=52

function archer:attack(target)
 --use the bow
end

arcgob1=archer:new(20,50)
arcgob2=archer:new(40,70)

look at this from bottom to top:

  • arcgob1.x will be 20, y 50
  • arcgob1’s and arcgob2’s prototype is archer, because when we call archer:new, self on line 6 of my first code block points to archer
  • arcgob1.sp is 52 (the value comes from the prototype)
  • arcgob1:attack(hero) will use our archer:attack method.
  • arcgob1:draw() will use goblin:draw! archer itself is a table that has goblin for prototype
    draw is not found in arcgob1, look at its prototype archer, not found, look at its prototype goblin, found! call it with self pointing to arcgob1.

result:

the confusion is that we often see code like this to explain prototypes (or «class», but lua doesn’t have classes):

goblin={sp=42}

function goblin:new(obj)
 setmetatable(obj, self)
 self.__index=self
 return obj
end

why do we need to add goblin.__index = goblin?? it’s its own prototype? but it’s a metatable? both?!
the thing is, we don’t need that. a metatable is only strictly required to implement metamethods to define what operators do. when we want a prototype, {__index=proto} is the metatable, and proto the prototype. clarity at last!)

hope this helps! please ask follow-up questions if needed, try to implement your own cart and share it!

P#147311 2024-04-25 16:35
[ :: Read More :: ]

Cart #dashplus1-0 | 2024-04-25 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#147307 2024-04-25 15:54 ( Edited 2024-04-25 15:54)
[ :: Read More :: ]

Greetings,

I'm relatively new to the Picotron and even though it is a "fantasy workstation" I was wondering if there was a way to use it as an actual OS specifically for the Raspberry Pi. If anyone knows if there is a way to use it as an ISO for a Raspberry Pi I would love to get some info as to learning how to make it it's own OS.

P#147303 2024-04-25 14:56
[ :: Read More :: ]

Cart #bad_rooms_ld55-2 | 2024-04-28 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
3

Ludum Dare 55 entry

X/C cycle spells + Arrow keys to move
1-4 players vs 0-3 CPU players (max 4)

P#147290 2024-04-25 10:53 ( Edited 2024-04-28 13:53)
[ :: Read More :: ]

Cart #rebooter_-0 | 2024-04-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
8

--REBOOTER--

Ordered by Elevated Recovery
Made by Charlie Boudchicha (https://www.fiverr.com/charlie_boud)

You need to complete every achievements to win the game :

  • make a bad decision
  • make a productive decision
  • do something to rest
  • unlock the 4 blue rooms
  • go through 15 rooms
  • survive 3 trap rooms
P#147277 2024-04-24 22:14 ( Edited 2024-05-01 11:32)
[ :: Read More :: ]

Hello, considering the following:

Trying to remake Vampire Survivors and a fun project
I have a character class
Characters have effects that are applied to a target. In this example my target = player
I have a character that is an instance of that class. Let's call him "Antonio"
I have a "run", Antonio is copied into run.player
I set player to be run.player

My problem is that I have to initiate the character class and Antonio before I create "player". But player is not yet created so player referenced on the character class is nil.

I hope this makes sense, I have a workaround but it feels clunky and I'm wondering if there are other solutions.

Here is my code before the workaround:

character = {}
character.__index = character
function character:new(name)
    local o = setmetatable({}, character)
    o.name = name
    o.x = 0
    o.y = 0
    o.sp_scale = 1
    o.w = 16
    o.h = 16
    o.effects = effects
    o.original_invincibility_frames = 10
    o.invincibility_frames = 0
    o.max_health = 100
    o.health = 20
    o.recovery = 0
    o.armor = 0
    o.move_speed = 1
    o.might = 1
    o.weapon_projectile_speed = 0
    o.weapon_duration = 0
    o.weapon_area = 0
    o.weapon_cooldown = 0
    o.weapon_projectiles_amount = 0
    o.revival = 0
    o.magnet = 0
    o.luck = 0
    o.growth = 0
    o.greed = 0
    o.curse = 0
    o.reroll = 0
    o.skip = 0
    o.banish = 0
    return o
end

function character:set_effects(effects)
    self.effects = effects
end

function character:apply_effects(level)

    local effects = self.effects
    for _, effect in pairs(effects) do
        if level % effect.level_increment == 0 and 
            level <= effect.max_level_increment then 
            local target = effect.target    
            if effect.mode == "percent" then
                target[effect.stat] += (target[effect.stat] or 0) * effect.value
            else
                target[effect.stat] = (target[effect.stat] or 0) + effect.value
            end
        end

    end
end

antonio = character:new("antonio")
antonio.recovery = 0.5
antonio:set_effects( {

                    {   description="Gains 10% Might every 2 Levels",  
                        stat = "might", 
                        value = 1,
                        target = player, -- here is the problem, player doesn't exist
                        level_increment = 2,
                        max_level_increment = 10,
                        mode = "percent"
                    },
                    {   description="Gains 0.5 Recovery every 1 level", 

                        stat = "recovery", 
                        value = 0.5,
                        target = player,
                        level_increment = 1,
                        max_level_increment = 5
                    }

                }

)

function _init()
    t = 0
    run = {}
    run.player = {}
    run.level = 1
    add(run.player, deepcopy(antonio))

    player = run.player[1]

end

function _update()

    if t % 60 == 0 then player.health += player.recovery end 
    if btnp(4) then
        run.level += 1
        player:apply_effects(run.level)
    end
    t += 1
end

function _draw()
    local y = 0
    cls(0)
    for entry in all(run.player) do
        for k, v in pairs(entry) do
            if type(v) == "number" then
                print(k..":"..v, 0, y)
                y += 8
            end
        end
    end
    local y = 0
    print("Level: "..run.level, 240, y)

end

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, getmetatable(orig))
    else -- for numbers, strings, booleans, etc
        copy = orig
    end
    return copy

end

And here is my code with the workaround, in short, once player is created I go and apply player as the target of the effects: player:update_effects_target(player)

character = {}
character.__index = character
function character:new(name)
    local o = setmetatable({}, character)
    o.name = name
    o.x = 0
    o.y = 0
    o.sp_scale = 1
    o.w = 16
    o.h = 16
    o.effects = effects
    o.original_invincibility_frames = 10
    o.invincibility_frames = 0
    o.max_health = 100
    o.health = 20
    o.recovery = 0
    o.armor = 0
    o.move_speed = 1
    o.might = 1
    o.weapon_projectile_speed = 0
    o.weapon_duration = 0
    o.weapon_area = 0
    o.weapon_cooldown = 0
    o.weapon_projectiles_amount = 0
    o.revival = 0
    o.magnet = 0
    o.luck = 0
    o.growth = 0
    o.greed = 0
    o.curse = 0
    o.reroll = 0
    o.skip = 0
    o.banish = 0
    return o
end

function character:set_effects(effects)
    self.effects = effects
end

function character:update_effects_target(target)
    for _, effect in pairs(self.effects) do
        effect.target = target
    end
end

function character:apply_effects(level)

    local effects = self.effects
    for _, effect in pairs(effects) do
        if level % effect.level_increment == 0 and 
            level <= effect.max_level_increment then 
            local target = effect.target    
            if effect.mode == "percent" then
                target[effect.stat] += (target[effect.stat] or 0) * effect.value
            else
                target[effect.stat] = (target[effect.stat] or 0) + effect.value
            end
        end

    end
end

antonio = character:new("antonio")
antonio.recovery = 0.5
antonio:set_effects( {

                    {   description="Gains 10% Might every 2 Levels",  
                        stat = "might", 
                        value = 1,
                        target = player, -- here is the problem, player doesn't exist
                        level_increment = 2,
                        max_level_increment = 10,
                        mode = "percent"
                    },
                    {   description="Gains 0.5 Recovery every 1 level", 

                        stat = "recovery", 
                        value = 0.5,
                        target = player,
                        level_increment = 1,
                        max_level_increment = 5
                    }

                }

)

function _init()
    t = 0
    run = {}
    run.player = {}
    run.level = 1
    add(run.player, deepcopy(antonio))

    player = run.player[1]
    player:update_effects_target(player)
end

function _update()

    if t % 60 == 0 then player.health += player.recovery end 
    if btnp(4) then
        run.level += 1
        player:apply_effects(run.level)
    end
    t += 1
end

function _draw()
    local y = 0
    cls(0)
    for entry in all(run.player) do
        for k, v in pairs(entry) do
            if type(v) == "number" then
                print(k..":"..v, 0, y)
                y += 8
            end
        end
    end
    local y = 0
    print("Level: "..run.level, 240, y)

end

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, getmetatable(orig))
    else -- for numbers, strings, booleans, etc
        copy = orig
    end
    return copy

end
P#147242 2024-04-24 10:32 ( Edited 2024-04-24 10:32)
[ :: Read More :: ]

I've been using this tutorial as my principal information for programming, since there's no picotron specific resource.

I'm experimenting with table-based classes, according to the guide I'm supposed to be able to create a base blueprint of an object and then instantiate it, but when I do so following the example, the object is not copied but instead it becomes a reference, because every change gets applied to the first object.

I made a sample project, first I try the guide's way, then I try it in a way I know works

enemies = {}
enemies2 = {}

enemy = {
    type = 0,
    sp = 1,
    x = 0,
    y = 0,
    dx = 0,
    dy = 0,
    update=function(self)
    self.x += self.dx
    self.y += self.dy  
  end,
    draw=function(self)
        spr(self.sp, self.x, self.y)
    end
}

goblin = enemy --copy enemy class
goblin.sp = 2
goblin.type = 3
goblin.x = 6
goblin.y = 10

ogre = enemy  --copy enemy class
ogre.sp = 3
ogre.type = 4
ogre.x = 40
ogre.y = 50

function _init()
add(enemies, enemy)
add(enemies, goblin)
add(enemies, ogre)

add_enemy(16,16,4)
add_enemy(32,32,5)
add_enemy(64,64,6)

end

function add_enemy(new_x,new_y,sprIndex)
    add(enemies2, {
    type = 0,
    sp = sprIndex,
    x = new_x,
    y = new_y,
    dx = 0,
    dy = 0,
    update=function(self)
        self.x += self.dx
        self.y += self.dy  
    end,
    draw=function(self)
        spr(self.sp, self.x, self.y)
    end
})
end

function _draw()
    for e in all(enemies) do
        e:draw()
    end

    for en in all(enemies2) do
        en:draw()
    end
end

If I define the object in the add function then each object acts as independent object, is this how tables are supposed to function?

Cart #tihuwubibu-0 | 2024-04-24 | Embed ▽ | License: CC4-BY-NC-SA
2

P#147234 2024-04-24 09:11
[ :: Read More :: ]

Cart #basic_platformer_mecanics-0 | 2024-04-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
2

P#147232 2024-04-24 08:06
[ :: Read More :: ]

Cart #duwiramope-0 | 2024-04-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
3


jus a little wip game

P#147225 2024-04-24 02:35
[ :: Read More :: ]

hi, i'm loving picotron so far! i just wanted to report some issues using coroutines.

when using coroutine.resume, it can sometimes return early when the coroutine runs for a while due to how picotron does timeslicing. from reading head.lua, i learned that using coresume instead of coroutine.resume fixes this, which makes me think maybe coroutine.resume should be replaced with it. another more minor issue is that coresume only returns the first value of a multiple-value return/yield from the coroutine, and not any more.

here's a simple test case:

local function long_running_coroutine ()
  for i = 1, 100 do
    cls()
  end
  return 1, 2
end

function working ()
  local c = coroutine.create (long_running_coroutine)
  coresume (c)
  assert (coroutine.status(c) == 'dead', 'this works')
end

function not_working ()
  local c = coroutine.create (long_running_coroutine)
  coroutine.resume (c)
  assert (coroutine.status(c) == 'dead', 'this doesn\'t work')
end

function also_not_working ()
  local c = coroutine.create (long_running_coroutine)
  local a, b, c = coresume (c)
  assert (a)
  assert (b)
  assert (c, 'only one coroutine return value returned')
end

function _draw ()
  working ()
  not_working ()
  also_not_working ()
end
P#147216 2024-04-23 22:47 ( Edited 2024-04-24 02:00)
[ :: Read More :: ]

Cart #pgui-5 | 2024-05-08 | Embed ▽ | License: CC4-BY-NC-SA
25

A GUI library for Picotron!

It includes basic components: boxes, text boxes, text input, buttons, sliders, radio and multiple selection buttons, and color selecter. And layout components: vertical and horizontal stacks, dropdowns, a topbar and a scrollable container.

It can be useful to test game mechanics or to build app interfaces.

You can use this cart and see how it works or check the documentation on the github repository.

(I'll try to make a video on how to use it and post it here too :))

Here's one simple example:

include "pgui.lua"

function _init()
  -- Define the initial value of the slider
    slidervalue = 10
end

function _update()
  -- Refresh pgui each frame
    pgui:refresh()

  -- Create a slider and set its value back from its return value
    slidervalue = pgui:component("hslider",{pos=vec(190,20),value=slidervalue})
end

function _draw()
    cls(5)

  -- Draw the circle, its size is based on the return value of the slider
    circfill(240,140,slidervalue,8)

   -- Draw all pgui components  
    pgui:draw()
end

Let me know if you use it for any projects or if you have improvement ideas!

Note: keyboard text input is not currently working on the online version

Changelog:

1.0.1:

  • Added layers option
  • Improved dropdown (now the content is shown one layer on top)
  • Minor performance improvements

1.0.2:

  • Fixed offset error in scrollable and fixed button response miscalculations inside scrollable
  • Added flr option to hslider
  • Fixed minor layout adjustments
  • Added sprite_box component based on @MaddoScientisto's suggestion
  • Fixed color palette not being passed to children components

1.0.3

  • Performance update, now components consume less cpu
  • Refactored codebase to make it cleaner and easier to expand
  • Minor display improvements in hslider
  • Fixed color palette change function

P#147208 2024-04-23 20:47 ( Edited 2024-05-08 17:52)
[ :: Read More :: ]

Cart #lens-3 | 2024-04-23 | Embed ▽ | License: CC4-BY-NC-SA
6

Lens 0.1.2

Capture and view debugging information. This app will run and allow you to send it values to log and inspect. Since this runs as a separate process, you can still inspect log values even in the event of your program crashing.

Supports all data types and includes the ability to inspect table values.

Usage

To use, include "libs/lens.lua" from the cart, and call Lens.log().

Otherwise just send a "log" event to the lens process:

send_message(lens_pid, {
    event = "log",
    value = "log output",
})

This is an early release to collect feedback, so please let me know if you find it useful or any issues you encounter.

P#147194 2024-04-23 14:46 ( Edited 2024-04-23 22:21)
[ :: Read More :: ]

Cart #dashlessplus-0 | 2024-04-23 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#147190 2024-04-23 13:28
View Older Posts